package com.dynamic.mybatis.core.metadata;


import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.dynamic.mybatis.core.builder.DynamicMapperAdapterBuilder;
import com.dynamic.mybatis.core.toolkit.BeanUtil;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.logging.LogFactory;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMap;
import org.apache.ibatis.mapping.ResultMap;
import org.apache.ibatis.parsing.XNode;

import java.util.Map;
import java.util.Objects;

public class DynamicConfiguration extends MybatisConfiguration{
    private static final Log logger = LogFactory.getLog(DynamicConfiguration.class);
    protected final Map<String, DynamicMappedStatement> dynamicMappedStatements =  new StrictMap<DynamicMappedStatement>("Dynamic Mapped Statement Attributes collection").conflictMessageProducer((savedValue, targetValue) -> ". please check " + savedValue.toString() + " and " + targetValue.toString());
    public  final String DYNAMIC_NAMESPACE = "com.dynamic.mybatis.DynamicMappedStatement";
    public  final String DYNAMIC_RESOURCE = "com.dynamic.mybatis.DynamicMappedStatement";

    public DynamicMappedStatement getDynamicMappedStatement(String mappedStatementId) {
        if(dynamicMappedStatements.containsKey(mappedStatementId)){
            return dynamicMappedStatements.get(mappedStatementId);
        }
       /*
        *  返回namespace相同的父节点
        *  解决DynamicMappedStatement.mappedStatement中有多个映射语句 只会dynamicMappedStatements只会加入解决DynamicMappedStatement.id对应的DynamicMappedStatement
       */
        MappedStatement mappedStatement = getMappedStatement(mappedStatementId);
        if(mappedStatement  != null){
            String id = mappedStatement.getId();
            String [] namespaces  = id.split("\\.");
            if(namespaces != null && namespaces.length > 1){
                String parentId = namespaces[namespaces.length-2];
                if(dynamicMappedStatements.containsKey(parentId)){
                    return dynamicMappedStatements.get(parentId);
                }
            }
        }
        return null;
    }



    public Map<String, DynamicMappedStatement> getDynamicMappedStatements() {
        return dynamicMappedStatements;
    }


    public boolean isResourceLoaded(String resource) {
        if(!DYNAMIC_RESOURCE.equals(resource)){
            return loadedResources.contains(resource);
        }
        return false;
    }

    public Boolean hasMappedStatement(String id) {
        return  mappedStatements.containsKey(id);
    }

    public void addDynamicMappedStatement(DynamicMappedStatement dms) {
        logger.debug("addDynamicMappedStatement: " + dms.getId());
        if (dynamicMappedStatements.containsKey(getShortName(dms.getId()))) {
            if(!Objects.equals(getShortName(dms.getId()),dms.getId())){
                dynamicMappedStatements.remove(getShortName(dms.getId()));
            }
            dynamicMappedStatements.remove(dms.getId());
            dynamicMappedStatements.remove(DYNAMIC_NAMESPACE+"."+dms.getId());
        }
       dynamicMappedStatements.put(dms.getId(),dms);
    }

    @Override
    public void addMappedStatement(MappedStatement ms) {
        logger.debug("addMappedStatement: " + ms.getId());
        if (mappedStatements.containsKey(getShortName(ms.getId()))) {
            if(!Objects.equals(getShortName(ms.getId()),ms.getId())){
                mappedStatements.remove(getShortName(ms.getId()));
                dynamicMappedStatements.remove(getShortName(ms.getId()));
            }
            mappedStatements.remove(ms.getId());
            dynamicMappedStatements.remove(DYNAMIC_NAMESPACE+"."+ms.getId());
        }
        super.addMappedStatement(ms);
    }

    @Override
    public void addParameterMap(ParameterMap pm) {
        logger.debug("addParameterMap: " + pm.getId());
        if (parameterMaps.containsKey(getShortName(pm.getId()))) {
            if(!Objects.equals(getShortName(pm.getId()),pm.getId())){
                dynamicMappedStatements.remove(getShortName(pm.getId()));
            }
            resultMaps.remove(pm.getId());
            dynamicMappedStatements.remove(DYNAMIC_NAMESPACE+"."+pm.getId());
        }
        super.addParameterMap(pm);
    }

    @Override
    public void addResultMap(ResultMap rm) {
        logger.debug("addResultMap: " + rm.getId());
        if (resultMaps.containsKey(getShortName(rm.getId()))) {
            resultMaps.remove(rm.getId());
            dynamicMappedStatements.remove(DYNAMIC_NAMESPACE+"."+rm.getId());
        }
        super.addResultMap(rm);
    }

    public void addSqlFragments(Map<String,XNode> xNodes) {
        sqlFragments.putAll(xNodes);
    }


    private String getShortName(String key) {
        final String[] keyParts = key.split("\\.");
        return keyParts[keyParts.length - 1];
    }

    public  DynamicConfiguration clone() {
        this.getMappedStatements();
        DynamicConfiguration dc =  BeanUtil.copy(this);
        DynamicMapperAdapterBuilder parser = new DynamicMapperAdapterBuilder(dc);
        this.dynamicMappedStatements.forEach((key,value) -> parser.parser(BeanUtil.copy(value)));
        dc.setEnvironment(this.environment);
        return dc;
    }


}
